﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Security.Cryptography;
using System.Xml;
using System.IO;

namespace DigitalSignature_CSharp
{
    public partial class Form1 : Form
    {
        private RSACryptoServiceProvider RSAProvider;
        String hash_result = "";

        public Form1()
        {
            InitializeComponent();
        }

        private void btnGenKey_Click_1(object sender, EventArgs e)
        {
            int iKeySize = int.Parse(tbKeySize.Text.Trim());
            RSAProvider = new RSACryptoServiceProvider(iKeySize);
            RSAProvider.PersistKeyInCsp = false;
            string rsaProperty = RSAProvider.ToXmlString(true);
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(rsaProperty);

            string publicKey = ((XmlElement)doc.GetElementsByTagName("Modulus").Item(0)).InnerText;
            string privateKey = ((XmlElement)doc.GetElementsByTagName("D").Item(0)).InnerText;

            lbPublicKey.Text = publicKey;
            lbPrivateKey.Text = privateKey;
        }

        private void selectFile_1(int flag)
        {
            OpenFileDialog choiceFileDlg = new OpenFileDialog();
            choiceFileDlg.RestoreDirectory = true;
            switch (flag)
            {
                case 0:
                    choiceFileDlg.Title = "Choice private key file";
                    break;
                case 1:
                    choiceFileDlg.Title = "Choice file to create Signature";
                    break;
                case 2:
                    choiceFileDlg.Title = "Choice public key file";
                    break;
                case 3:
                    choiceFileDlg.Title = "Choice file to check Signature";
                    break;
                default:
                    break;
            }


            if (choiceFileDlg.ShowDialog() == DialogResult.OK)
                switch (flag)
                {
                    case 0:
                        tbInputFile_Public_1.Text = choiceFileDlg.FileName;
                        break;
                    case 1:
                        tbInputFile_2.Text = choiceFileDlg.FileName;
                        break;
                    case 2:
                        tbInputFile_Public.Text = choiceFileDlg.FileName;
                        break;
                    case 3:
                        tbInputFile_1.Text = choiceFileDlg.FileName;
                        break;
                    default:
                        break;
                }
        }

        private void btnPrivate_Click(object sender, EventArgs e)
        {
            selectFile_1(0);
        }

        private void btnInput_1_Click(object sender, EventArgs e)
        {
            selectFile_1(1);
        }

        private void btnBowse_publicFile_Click(object sender, EventArgs e)
        {
            selectFile_1(2);
        }

        private void btnInput_2_Click(object sender, EventArgs e)
        {
            selectFile_1(3);
        }

        static string GetMd5Hash(HashAlgorithm md5Hash, string input)
        {

            // Convert the input string to a byte array and compute the hash.
            byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));

            // Create a new Stringbuilder to collect the bytes
            // and create a string.
            StringBuilder sBuilder = new StringBuilder();

            // Loop through each byte of the hashed data 
            // and format each one as a hexadecimal string.
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }

            // Return the hexadecimal string.
            return sBuilder.ToString();
        }

        // Verify a hash against a string.
        static bool VerifyMd5Hash(HashAlgorithm md5Hash, string input, string hash)
        {
            // Hash the input.
            string hashOfInput = GetMd5Hash(md5Hash, input);

            // Create a StringComparer an compare the hashes.
            StringComparer comparer = StringComparer.OrdinalIgnoreCase;

            if (0 == comparer.Compare(hashOfInput, hash))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public String Create_Hash(string Hash_Mode, string fileIn)
        {
            //StreamWriter sw = new StreamWriter(fileOut);
            //StreamReader sr = File.OpenText(fileIn);

            if (!File.Exists(fileIn))
            {
                MessageBox.Show(fileIn + " does not exist.");
                return "-1";
            }
             

            String input = File.ReadAllText(fileIn);

            HashAlgorithm func_hash = new MD5CryptoServiceProvider();

            switch (Hash_Mode)
            {
                case "SHA1":
                    func_hash = new SHA1CryptoServiceProvider();
                    break;
                case "MD5":
                    func_hash = new MD5CryptoServiceProvider();
                    break;
                case "SHA256":
                    func_hash = new SHA256CryptoServiceProvider();
                    break;
                case "SHA384":
                    func_hash = new SHA384CryptoServiceProvider();
                    break;
                case "SHA512":
                    func_hash = new SHA512CryptoServiceProvider();
                    break;
            }

            String result = GetMd5Hash(func_hash, input);
            //sw.Write(result);

            //sw.Close();
            return result;
        }

        public static byte[] StrToByteArray(string str)
        {
            System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
            return encoding.GetBytes(str);
        }

        private void btnCreateSign_Click(object sender, EventArgs e)
        {
            /*
            String strSavePath = "";
            string szPrivKey = tbInputFile_Public_1.Text;

            if (tbInputFile_2.Text == "")
            {
                MessageBox.Show("Chua du thong so !");
                return;
            }

            try
            {
                hash_result = Create_Hash("MD5", tbInputFile_2.Text);
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("Error!");
                return;
            }


            int iPosition;

            for (iPosition = tbInputFile_2.Text.Length - 1; iPosition >= 0; iPosition--)
                if (tbInputFile_2.Text[iPosition] == '.')
                    break;

            strSavePath = tbInputFile_2.Text.Substring(0,iPosition);
            strSavePath += ".sig";

           FileStream fsPubkey = null, fsOutput = null;
            try
            {
                string szFileEnc = strSavePath;

                fsPubkey = new FileStream(szPrivKey, FileMode.Open, FileAccess.Read);
                fsOutput = new FileStream(szFileEnc, FileMode.Create, FileAccess.Write);

                RSACryptoServiceProvider myRSA = new RSACryptoServiceProvider();

                byte[] bytePrivkey = new byte[fsPubkey.Length];
                fsPubkey.Read(bytePrivkey, 0, bytePrivkey.Length);
                myRSA.FromXmlString(ASCIIEncoding.ASCII.GetString(bytePrivkey, 0, bytePrivkey.Length));

                byte[] byteInput = StrToByteArray(hash_result);

                byte[] byteEnc;
                byteEnc = myRSA.Encrypt(byteInput, false);
                fsOutput.Write(byteEnc, 0, byteEnc.Length);

                fsPubkey.Close();
                fsOutput.Close();
            }
            catch (CryptographicException ex)
            {
                MessageBox.Show("Error: " + ex);
                fsPubkey.Close();
                fsOutput.Close();
                return;
            }

            MessageBox.Show("Mã tạo chữ ký thành công!");
             */
            String iFile = tbInputFile_2.Text;
            FileStream iStream = new FileStream(iFile, FileMode.Open, FileAccess.Read);
            //int currHashIndex = listHashType.SelectedIndex;

            SHA1 hashObj = new SHA1CryptoServiceProvider();
            int nTotalByteInput = (int)iStream.Length;

            byte[] inData = new byte[nTotalByteInput];
            iStream.Read(inData, 0, nTotalByteInput);

            byte[] hashData = hashObj.ComputeHash(inData);

            StringBuilder returnValue = new StringBuilder();

            FileStream fsPrivkey = null;
            try
            {
                string szPrivKey = tbInputFile_Public_1.Text;
                fsPrivkey = new FileStream(szPrivKey, FileMode.Open, FileAccess.Read);
                RSACryptoServiceProvider myRSA = new RSACryptoServiceProvider();

                byte[] bytePrivkey = new byte[fsPrivkey.Length];
                fsPrivkey.Read(bytePrivkey, 0, bytePrivkey.Length);
                String priKey = ASCIIEncoding.ASCII.GetString(bytePrivkey, 0, bytePrivkey.Length);

                myRSA.FromXmlString(priKey);
                RSAPKCS1SignatureFormatter signer = new RSAPKCS1SignatureFormatter(myRSA);
                signer.SetHashAlgorithm("SHA1");

                byte[] signature = signer.CreateSignature(hashData);
                fsPrivkey.Close();

                String outputFile = iFile + ".sig";
                BinaryWriter outStream = new BinaryWriter(new FileStream(outputFile, FileMode.Create, FileAccess.Write));

                outStream.Write(signature);
                outStream.Flush();
                outStream.Close();
                iStream.Close();
                MessageBox.Show("Saved to " + outputFile);
            }
            catch (CryptographicException ex)
            {
                MessageBox.Show("Error: " + ex);
                fsPrivkey.Close();
                return;
            }
        }

        public bool Check(string Hash_Mode, string fileIn, string hash)
        {
            //StreamReader sr_inp = File.OpenText(fileIn);
            //StreamReader sr_out = File.OpenText(fileOut);

            String input = File.ReadAllText(fileIn);
            //String hash = File.ReadAllText(fileOut);

            HashAlgorithm func_hash = new MD5CryptoServiceProvider();

            switch (Hash_Mode)
            {
                case "SHA1":
                    func_hash = new SHA1CryptoServiceProvider();
                    break;
                case "MD5":
                    func_hash = new MD5CryptoServiceProvider();
                    break;
                case "SHA256":
                    func_hash = new SHA256CryptoServiceProvider();
                    break;
                case "SHA384":
                    func_hash = new SHA384CryptoServiceProvider();
                    break;
                case "SHA512":
                    func_hash = new SHA512CryptoServiceProvider();
                    break;
            }

            if (VerifyMd5Hash(func_hash, input, hash))
                return true;
            else
                return false;
        }

        private void btnChekSign_Click(object sender, EventArgs e)
        {
            /*
            String strSavePath = "";

            if (tbInputFile_1.Text == "")
            {
                MessageBox.Show("Chua du thong so !");
                return;
            }

            int iPosition;

            for (iPosition = tbInputFile_1.Text.Length - 1; iPosition >= 0; iPosition--)
                if (tbInputFile_1.Text[iPosition] == '.')
                    break;

            strSavePath = tbInputFile_1.Text.Substring(0, iPosition);
            strSavePath += ".sig";

            FileStream fsPrivkey = null, fsInput = null;
            //fsOutput = null;
            try
            {
                string szPrivKey = tbInputFile_Public.Text;
                string szFileInput = strSavePath;

                fsPrivkey = new FileStream(szPrivKey, FileMode.Open, FileAccess.Read);
                
                try
                {
                    fsInput = new FileStream(szFileInput, FileMode.Open, FileAccess.Read);
                }
                catch (System.Exception ex)
                {
                    MessageBox.Show("File khong ton tai !");
                    return;
                }
                
                //fsOutput = new FileStream(szFileEnc, FileMode.Create, FileAccess.Write);

                RSACryptoServiceProvider myRSA = new RSACryptoServiceProvider();

                byte[] bytePrivkey = new byte[fsPrivkey.Length];
                fsPrivkey.Read(bytePrivkey, 0, bytePrivkey.Length);
                myRSA.FromXmlString(ASCIIEncoding.ASCII.GetString(bytePrivkey, 0, bytePrivkey.Length));

                System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();

                byte[] byteInput = new byte[fsInput.Length];
                fsInput.Read(byteInput, 0, byteInput.Length);

                MessageBox.Show(enc.GetString(byteInput));

                byte[] byteDec;
                byteDec = myRSA.Decrypt(byteInput, false);

                //fsOutput.Write(byteDec, 0, byteDec.Length);
                
                hash_result = enc.GetString(byteDec);

                fsInput.Close();
                fsPrivkey.Close();
                //fsOutput.Close();
            }
            catch (CryptographicException ex)
            {
                MessageBox.Show("Error: " + ex);
                fsInput.Close();
                fsPrivkey.Close();
                return;
            }

            if (Check("MD5", tbInputFile_1.Text, hash_result))
                MessageBox.Show("Khop!");
            else
                MessageBox.Show("Khong khop!");
             */

            String iFile = tbInputFile_1.Text;
            FileStream iStream = new FileStream(iFile, FileMode.Open, FileAccess.Read);
            //int currHashIndex = listHashType.SelectedIndex;
            HashAlgorithm hashObj = SHA1.Create();

            int nTotalByteInput = (int)iStream.Length;

            byte[] iData = new byte[nTotalByteInput];
            iStream.Read(iData, 0, nTotalByteInput);

            byte[] hashData = hashObj.ComputeHash(iData);
            iStream.Close();
            StringBuilder returnValue = new StringBuilder();

            FileStream fsPubkey = null;
            try
            {
                string szPrubKey = tbInputFile_Public.Text;
                fsPubkey = new FileStream(szPrubKey, FileMode.Open, FileAccess.Read);
                RSACryptoServiceProvider myRSA = new RSACryptoServiceProvider();

                byte[] bytePubkey = new byte[fsPubkey.Length];
                fsPubkey.Read(bytePubkey, 0, bytePubkey.Length);
                String pubKey = ASCIIEncoding.ASCII.GetString(bytePubkey, 0, bytePubkey.Length);

                myRSA.FromXmlString(pubKey);
                RSAPKCS1SignatureDeformatter signer = new RSAPKCS1SignatureDeformatter(myRSA);
                signer.SetHashAlgorithm("SHA1");

                String signedFile = iFile + ".sig";
                FileStream fsSignedFile = new FileStream(signedFile, FileMode.Open, FileAccess.Read);
                byte[] signed = new byte[fsSignedFile.Length];
                fsSignedFile.Read(signed, 0, signed.Length);

                MessageBox.Show("Check sign: " + signer.VerifySignature(hashData, signed));
                fsPubkey.Close();
                fsSignedFile.Close();
            }
            catch (CryptographicException ex)
            {
                MessageBox.Show("Error: " + ex);
                fsPubkey.Close();
                return;
            }
        }

        private void bSave_1_Click(object sender, EventArgs e)
        {
            SaveFileDialog choiceFileDlg = new SaveFileDialog();
            choiceFileDlg.Title = "Save Public Key As";
            choiceFileDlg.Filter = "xml |*.xml";

            if (choiceFileDlg.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    FileStream fsPub = new FileStream(choiceFileDlg.FileName, FileMode.Create, FileAccess.Write);
                    byte[] bytePubkey = ASCIIEncoding.ASCII.GetBytes(RSAProvider.ToXmlString(false));
                    fsPub.Write(bytePubkey, 0, bytePubkey.Length);
                    fsPub.Close();
                }
                catch (Exception Ex)
                {
                    Console.WriteLine(Ex.Message);
                    return;
                }
            }
			
			int x = 10;
        }

        private void bSave_2_Click(object sender, EventArgs e)
        {
            SaveFileDialog choiceFileDlg = new SaveFileDialog();
            choiceFileDlg.Title = "Save Private Key As";
            choiceFileDlg.Filter = "xml |*.xml";

            if (choiceFileDlg.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    FileStream fsPriv = new FileStream(choiceFileDlg.FileName, FileMode.Create, FileAccess.Write);
                    byte[] bytePrivkey = ASCIIEncoding.ASCII.GetBytes(RSAProvider.ToXmlString(true));
                    fsPriv.Write(bytePrivkey, 0, bytePrivkey.Length);
                    fsPriv.Close();
                }
                catch (Exception Ex)
                {
                    Console.WriteLine(Ex.Message);
                    return;
                }
            }
        }
    }
}
